fix(solid-form): generate an SSR-safe default formId - #2263
Conversation
`createForm` never passed a `formId` to `FormApi`, so it fell back to
`uuid()`, which is seeded from `Math.random()` and therefore differs
between the server render and the client render. Binding it
(`<form id={form.formId}>`) produced a hydration mismatch under
SolidStart.
Use Solid's `createUniqueId()` for the default instead, which is what
the other adapters already do:
- react-form/src/useFormId.ts — React.useId, falling back to useUUID on React 17
- preact-form/src/useFormId.ts — useId from preact/hooks
- vue-form/src/useFormId.ts — Vue's useId, added in TanStack#2259
An explicitly provided `formId` is still preserved.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthrough
ChangesSolid form ID generation
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.changeset/great-pugs-shave.md:
- Line 5: Update the changeset description to state that createForm lacked an
SSR-safe fallback formId when options.formId was not provided, while
acknowledging explicit formId values were already forwarded. Capitalize React,
Preact, and Vue.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a9093e8e-c3b3-46d7-9424-841669e144dc
📒 Files selected for processing (3)
.changeset/great-pugs-shave.mdpackages/solid-form/src/createForm.tsxpackages/solid-form/tests/createFormId.test.tsx
An explicitly provided `formId` was already forwarded to `FormApi`; only the fallback was missing. Say that, and capitalize the framework names. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Good catch — corrected in c3d1e40. Explicit Worth noting the test file already documented this: |
Changes
When no
formIdis configured,createFormprovides no fallback, soFormApigenerates a randomuuid()— seeded fromMath.random(), and therefore different between the server render and the client render. Binding that generated id produces a hydration mismatch under SolidStart:An explicitly provided
formIdwas already forwarded and is unchanged by this PR.This is the same bug as #2254, which #2259 fixed for Vue. Solid is the remaining adapter with an SSR story that hadn't had the treatment the others already have:
react-form/src/useFormId.ts—React.useId, falling back touseUUIDon React 17preact-form/src/useFormId.ts—useIdfrompreact/hooksvue-form/src/useFormId.ts— Vue'suseId(fix(vue-form): generate an SSR-safe default formId #2259)Solid's counterpart is
createUniqueId(), which derives the id from the hydration context when one is present, so both renders agree.packages/solid-form/src/createForm.tsxnow uses it for the default.Test plan
packages/solid-form/tests/createFormId.test.tsxcovers both branches — an explicitformIdis returned unchanged, and the default comes from Solid's id sequence rather than a random uuid. Before the change the second test fails with:The first test passes both before and after, which is the evidence that explicit ids were never affected.
Full
@tanstack/solid-formsuite passes (46 tests, 5 files),tsc --noEmitis clean, andeslint ./src ./testsreports no new problems.One thing worth flagging
I wasn't able to assert the server/client round-trip directly the way
vue-form/tests/useFormId.test.tsxdoes. Under solid-form's current vitest config,solid-js/webresolves to the client build —isServerisfalseandrenderToString()returnsundefined— so an SSR render can't be exercised without a second vitest project configured with server conditions andsolid({ ssr: true }).Rather than grow this PR into a test-infrastructure change, the test pins the default to Solid's id sequence, which is the property that makes hydration agree. Happy to add the SSR project setup here or in a follow-up if you'd prefer the stronger assertion — just say which.
Summary by CodeRabbit
Bug Fixes
Tests